package com.mytv.dao;

import java.io.Serializable;
import java.util.List;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

/**
 * Implementation of access to db objects
 * @author Sirius
 * @param <T> Table od DB
 * @param <PK> Type of primary key of table
 */
@Repository
@Transactional
public class DaoImpl<T extends IEntity, PK extends Serializable> extends HibernateDaoSupport implements Dao<T, PK> {

    /**
     * Create a new entity instance for access to DB
     * @param sessionFactory 
     */
    @Autowired
    public DaoImpl(SessionFactory sessionFactory) {
        super.setSessionFactory(sessionFactory);
    }

    /**
     * Save object
     * @param o Object to save
     * @return Primary key of object saved
     */
    @Transactional(readOnly=false)
    @Override
    public PK save(T o) {
        return (PK) getHibernateTemplate().save(o);
    }

    /**
     * Update object
     * @param o  Object to update
     */
    @Transactional(readOnly=false)
    @Override
    public void update(T o) {
        getHibernateTemplate().update(o);
    }

    /**
     * Delete object
     * @param o Object to delete
     */
    @Transactional(readOnly=false)
    @Override
    public void delete(T o) {
        getHibernateTemplate().delete(o);
    }

    /**
     * Get object by primary key
     * @param type Type of entity
     * @param id Primary key of object
     * @return Object with primary key specified
     */
    @Transactional(readOnly=true)
    @Override
    public T get(Class<T> type, PK id) {
        return (T) getHibernateTemplate().get(type, id);
    }
    
    /**
     * Get object by primary key
     * @param name Name of entity
     * @param id Primary key of object
     * @return Object with primary key specified
     */
    @Transactional(readOnly=true)
    @Override
    public T get(String name, PK id) {
        return (T) getHibernateTemplate().get(name, id);
    }

    /**
     * Get the first response of query
     * @param criteria Selection criteria
     * @return First object of result
     */
    @Transactional(readOnly=true)
    @Override
    public T getUnique(DetachedCriteria criteria) {
        List<T> response = getHibernateTemplate().findByCriteria(criteria, 0, 1);
        if(response != null && !response.isEmpty()) {
            return response.get(0);
        }
        return null;
    }

    /**
     * Get response of query
     * @param criteria Selection criteria
     * @return List result of selection criteria
     */
    @Transactional(readOnly=true)
    @Override
    public List<T> get(DetachedCriteria criteria) {
        return getHibernateTemplate().findByCriteria(criteria);
    }

    /**
     * Get response of query
     * @param criteria Selection criteria
     * @param firstResult Index of first result
     * @param maxResults Num of results to read
     * @return Result list of selection criteria
     */
    @Transactional(readOnly=true)
    @Override
    public List<T> get(DetachedCriteria criteria, int firstResult, int maxResults) {
        return getHibernateTemplate().findByCriteria(criteria, firstResult, maxResults);
    }

    /**
     * Get by query
     * @param hql Query
     * @param values params in query
     * @return Result list of query
     */
    @Transactional(readOnly=true)
    @Override
    public List<T> get(String hql, Object... values) {
        return getHibernateTemplate().find(hql, values);
    }

    /**
     * Get all data by table
     * @param type Table DB
     * @return Result list of table
     */
    @Transactional(readOnly=true)
    @Override
    public List<T> getAll(Class<T> type) {
        return getHibernateTemplate().loadAll(type);
    }
    
    /**
     * Count data by criteria
     * @param criteria Selection criteria
     * @return Count the result data
     */
    @Transactional(readOnly=true)
    @Override
    public int count(DetachedCriteria criteria) {
        criteria.setProjection(Projections.rowCount());
        List response = getHibernateTemplate().findByCriteria(criteria);
        if(response != null && !response.isEmpty()) {
            return (Integer)response.get(0);
        }
        return 0;
    }

}